/* Start Header -------------------------------------------------------
Copyright (C) 2008 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the 
prior written consent of DigiPen Institute of Technology is prohibited.

File Name: InputControl.cpp
Purpose: Handling input
Language: C++ on Microsoft Visual Studio 2005
Platform: Microsoft Visual Studio 2005
          Supports shaders
Project: jmiller_CS300_1
Author: Jeremy Miller
        jmiller
        5002506
Creation date: 1 Oct 2008
- End Header --------------------------------------------------------*/
#include "InputControl.h"

#include <iostream>

DgtlProc Input::RegisterDgtlProc( MsgID id, DgtlState state, DgtlProc proc ) {
  DgtlMsgIter msgIter = digitalMap.find( id );
  if( msgIter == digitalMap.end() ) {
    // Msg does not exist, meaning state and proc do not exist
    DgtlMsgInsertIter msgPos = digitalMap.insert( MsgPair( id, DgtlStateMap() ) );
    if( msgPos.second ) {
      DgtlStateInsertIter statePos = msgPos.first->second.insert( StatePair( state, DgtlProcSet() ) );
      if( statePos.second ) {
        DgtlProcInsertIter procPos = statePos.first->second.insert( proc );
        if( procPos.second ) {
          RegisterMsgforUpdate( id );
          return proc; // Inserted proc
        }
      }
    }
  }
  else {
    DgtlStateMap& stateMap = msgIter->second;
    DgtlStateIter stateIter = stateMap.find( state );
    if( stateIter == stateMap.end() ) {
      // State does not exist, meaning proc does not exist
      DgtlStateInsertIter statePos = stateMap.insert( StatePair( state, DgtlProcSet() ) );
      if( statePos.second ) {
        DgtlProcInsertIter procPos = statePos.first->second.insert( proc );
        if( procPos.second ) {
          RegisterMsgforUpdate( id );
          return proc; // Inserted proc
        }
      }
    }
    else {
      DgtlProcSet& procSet = stateIter->second;
      DgtlProcSetIter procIter = procSet.find( proc );
      if( procIter == procSet.end() ) {
        // proc does not exist
        DgtlProcInsertIter procPos = procSet.insert( proc );
        if( procPos.second ) {
          RegisterMsgforUpdate( id );
          return proc; // Inserted proc
        }
        return NULL;
      }
      return proc; // Proc already exist
    }
  }
  return NULL;
}

DgtlProc Input::UnregisterDgtlProc( MsgID id, DgtlState state, DgtlProc proc ) {
  DgtlMsgIter msgIter = digitalMap.find( id );
  if( msgIter != digitalMap.end() ) {
    DgtlStateMap& statePos = msgIter->second;
    DgtlStateIter stateIter = statePos.find( state );
    if( stateIter != statePos.end() ) {
      DgtlProcSet& procPos = stateIter->second;
      DgtlProcSetIter procIter = procPos.find( proc );
      if( procIter != procPos.end() ) {
        procPos.erase( procIter );
      }
      else {
        return NULL;
      }

      if( !stateIter->second.size() ) {
        statePos.erase( stateIter );
      }
    }

    if( !msgIter->second.size() ) {
      digitalMap.erase( msgIter );
      UnregisterMsgforUpdate( id );
    }
  }

  return proc;
}

void Input::RegisterMsgforUpdate( MsgID id, DgtlState initState ) {
  curDgtlStates.insert( MsgStatePair( id, initState ) );
}

void Input::UnregisterMsgforUpdate( MsgID id ) {
  MsgStateIter iter = curDgtlStates.find( id );
  curDgtlStates.erase( iter );
}

void Input::Update() {
  MsgStateIter msBeg = curDgtlStates.begin();
  MsgStateIter msEnd = curDgtlStates.end();

  for( ; msBeg != msEnd; ++msBeg ) {
    DgtlMsgIter msgIter = digitalMap.find( msBeg->first );
    if( msgIter != digitalMap.end() ) {
      DgtlStateMap& statePos = msgIter->second;
      DgtlStateIter stateIter = statePos.find( msBeg->second );
      if( stateIter != statePos.end() ) {
        DgtlProcSet& procState = stateIter->second;
        DgtlProcSetIter procBeg = procState.begin();
        DgtlProcSetIter procEnd = procState.end();
        for( ; procBeg != procEnd; ++procBeg ) {
          (*procBeg)();
        }
      }
    }

    switch( msBeg->second ) {
      case TRIGGERED:
        msBeg->second = PRESSED;
        break;
      case RELEASED:
        msBeg->second = IDLE;
    }

  }
}

void Input::SetDown( MsgID id ) {
  MsgStateIter msIter = curDgtlStates.find( id );
  if( msIter != curDgtlStates.end() ) {
    switch( msIter->second ) {
      case RELEASED:
      case IDLE:
        msIter->second = TRIGGERED;
        break;
      case TRIGGERED:
        msIter->second = PRESSED;
        break;
    }
  }
}

void Input::SetUp( MsgID id ) {
  MsgStateIter msIter = curDgtlStates.find( id );
  if( msIter != curDgtlStates.end() ) {
    switch( msIter->second ) {
      case TRIGGERED:
      case PRESSED:
        msIter->second = RELEASED;
        break;
      case RELEASED:
        msIter->second = IDLE;
        break;
    }
  }
}


//void Input::RegAnlgProc( MsgID id, AnlgProc proc ) {
//}
